{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "d006b2ea-9dfe-49c7-88a9-a5a0775185fd",
   "metadata": {},
   "source": [
    "# Additional End of week Exercise - week 2\n",
    "\n",
    "Now use everything you've learned from Week 2 to build a full prototype for the technical question/answerer you built in Week 1 Exercise.\n",
    "\n",
    "This should include a Gradio UI, streaming, use of the system prompt to add expertise, and the ability to switch between models. Bonus points if you can demonstrate use of a tool!\n",
    "\n",
    "If you feel bold, see if you can add audio input so you can talk to it, and have it respond with audio. ChatGPT or Claude can help you, or email me if you have questions.\n",
    "\n",
    "I will publish a full solution here soon - unless someone beats me to it...\n",
    "\n",
    "There are so many commercial applications for this, from a language tutor, to a company onboarding solution, to a companion AI to a course (like this one!) I can't wait to see your results."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a07e7793-b8f5-44f4-aded-5562f633271a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# imports\n",
    "\n",
    "import os\n",
    "import json\n",
    "from dotenv import load_dotenv\n",
    "from openai import OpenAI\n",
    "import gradio as gr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2118e80a-6181-4488-95cf-c9da0500ea56",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Load environment variables in a file called .env\n",
    "# Print the key prefixes to help with any debugging\n",
    "\n",
    "load_dotenv(override=True)\n",
    "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
    "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
    "\n",
    "if openai_api_key:\n",
    "    print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
    "else:\n",
    "    print(\"OpenAI API Key not set\")\n",
    "    \n",
    "if google_api_key:\n",
    "    print(f\"Google API Key exists and begins {google_api_key[:8]}\")\n",
    "else:\n",
    "    print(\"Google API Key not set\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8ddc4764-e7f6-4512-8210-51bbfefbb3a9",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Set base url\n",
    "\n",
    "GEMINI_BASE_URL = \"https://generativelanguage.googleapis.com/v1beta/openai/\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "91bfd734-9c5e-4993-808e-b66489a92d4d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Connect to OpenAI, Anthropic and Google; comment out the Claude or Google lines if you're not using them\n",
    "\n",
    "openai = OpenAI()\n",
    "gemini = OpenAI(base_url=GEMINI_BASE_URL, api_key=google_api_key)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d9ee11ae-23e2-42cc-b63d-b446f6d83c99",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Set models\n",
    "\n",
    "gpt_model = \"gpt-4.1-mini\"\n",
    "gemini_model = \"gemini-2.0-flash\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a01d270e-f62e-41b3-8e46-ac173d7a1493",
   "metadata": {},
   "outputs": [],
   "source": [
    "system_gpt_prompt = \"You are an assistant with general knowledge obtained from the internet. \\\n",
    "Always respond with a cheerful tone. If you don’t know the answer to a question, simply say that you don’t know.\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4e85c8ed-3ba4-4283-8480-6979b0d5602f",
   "metadata": {},
   "outputs": [],
   "source": [
    "system_gemini_prompt = \"You are an expert translator with knowledge of all existing languages. \\\n",
    "Your only task is, given a provided sentence, to translate it into the specified target language. \\\n",
    "Do not provide anything else in your response only the translation itself.\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8ee0c887-a63f-48dd-8eaf-68b0bf9263b6",
   "metadata": {},
   "outputs": [],
   "source": [
    "def count_letter_tool(sentence, letter):\n",
    "\n",
    "    if len(letter) != 1:\n",
    "        return \"You need to provide a single letter to count\"\n",
    "    \n",
    "    return sentence.lower().count(letter.lower())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5f1ae918-cb99-4e60-80d3-37e16e514f55",
   "metadata": {},
   "outputs": [],
   "source": [
    "def translator_tool(sentence, language):\n",
    "    user_message = f\"Please translate this sentence: \\\"{sentence}\\\" to this language: {language}\"\n",
    "    messages = [{\"role\": \"system\", \"content\": system_gemini_prompt}, {\"role\": \"user\", \"content\":user_message}]\n",
    "    response = gemini.chat.completions.create(model=gemini_model, messages=messages)\n",
    "\n",
    "    return response.choices[0].message.content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2d499f2a-23b2-4fff-9d2d-f2333cbd109a",
   "metadata": {},
   "outputs": [],
   "source": [
    "count_letter_function = {\n",
    "    \"name\": \"count_letter_tool\",\n",
    "    \"description\": \"Count the number of a particular letter in a sentence. Call this whenever you need to know how many times a letter appears in a sentence, for example when a user asks 'How many 'a' are in this sentence?'\",\n",
    "    \"parameters\": {\n",
    "        \"type\": \"object\",\n",
    "        \"properties\": {\n",
    "            \"sentence\": {\n",
    "                \"type\": \"string\",\n",
    "                \"description\": \"The sentence provided by the user for counting.\"\n",
    "            },\n",
    "            \"letter\": {\n",
    "                \"type\": \"string\",\n",
    "                \"description\": \"The letter to count in the sentence.\"\n",
    "            }\n",
    "        },\n",
    "        \"required\": [\"sentence\", \"letter\"],\n",
    "        \"additionalProperties\": False\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b58079a8-8def-4fa6-8273-34bf8eeb8cb5",
   "metadata": {},
   "outputs": [],
   "source": [
    "translator_function = {\n",
    "    \"name\": \"translator_tool\",\n",
    "    \"description\": \"Translate a sentence provided by the user. Call this whenever a translation is needed, for example when a user asks 'Can you translate \\\"hola como estás?\\\" to English?'\",\n",
    "    \"parameters\": {\n",
    "        \"type\": \"object\",\n",
    "        \"properties\": {\n",
    "            \"sentence\": {\n",
    "                \"type\": \"string\",\n",
    "                \"description\": \"The sentence provided by the user to translate.\"\n",
    "            },\n",
    "            \"language\": {\n",
    "                \"type\": \"string\",\n",
    "                \"description\": \"The target language to translate the sentence into.\"\n",
    "            }\n",
    "        },\n",
    "        \"required\": [\"sentence\", \"language\"],\n",
    "        \"additionalProperties\": False\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7ab7fc93-3540-48e5-bbe0-3e9ad2bbce15",
   "metadata": {},
   "outputs": [],
   "source": [
    "tools = [{\"type\": \"function\", \"function\": count_letter_function}, {\"type\": \"function\", \"function\": translator_function}]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "678ccc37-c034-4035-bc3c-00fa8bcd8e64",
   "metadata": {},
   "outputs": [],
   "source": [
    "def chat(message, history):\n",
    "    messages = [{\"role\": \"system\", \"content\": system_gpt_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n",
    "    response = openai.chat.completions.create(model=gpt_model, messages=messages, tools=tools)\n",
    "\n",
    "    if response.choices[0].finish_reason==\"tool_calls\":\n",
    "        message = response.choices[0].message\n",
    "        response = handle_tool_call(message)\n",
    "        messages.append(message)\n",
    "        messages.append(response)\n",
    "        response = openai.chat.completions.create(model=gpt_model, messages=messages)\n",
    "    \n",
    "    return response.choices[0].message.content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2a1138e4-f849-4557-a74c-f9feb1572854",
   "metadata": {},
   "outputs": [],
   "source": [
    "def handle_tool_call(message):\n",
    "    tool_call = message.tool_calls[0]\n",
    "    arguments = json.loads(tool_call.function.arguments)\n",
    "    sentence = arguments.get('sentence')\n",
    "    response =\"\"\n",
    "    match tool_call.function.name:\n",
    "        case  \"translator_tool\":\n",
    "            language = arguments.get('language')\n",
    "            translation = translator_tool(sentence, language)\n",
    "            response = {\"role\": \"tool\", \"content\": json.dumps({\"translation\": translation}), \"tool_call_id\": tool_call.id}\n",
    "        case \"count_letter_tool\":\n",
    "            letter = arguments.get('letter')\n",
    "            count = count_letter_tool(sentence, letter)\n",
    "            response = {\"role\": \"tool\", \"content\": json.dumps({\"count\": count}), \"tool_call_id\": tool_call.id}\n",
    "\n",
    "    return response"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d39344cc-9e89-47a0-9249-2e182091ee43",
   "metadata": {},
   "outputs": [],
   "source": [
    "gr.ChatInterface(fn=chat, type=\"messages\").launch()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
